/**
 * Knot.cpp
 * Coyright (c) 2009 Xiaofeng Gu. All Rights Reserved.
 * Author : Xiaofeng Gu
 *
 * Creation Data : 2009/06/11
 */

#include "stdafx.h"
#include "Knot.h"
#include "Difference.h"
#include "Family.h"
#include "Global.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CKnot::CKnot(CFamily* pParent)
: m_pPath(NULL),
  m_Time(0),
  m_pParent(pParent),
  m_pTopNode(NULL)
{
	m_strKnotName = NODE_KNOT;
}

CKnot::~CKnot()
{
	for (Nodes::iterator it = m_Nodes.begin();
		it != m_Nodes.end(); it ++)
	{
		delete *it;
		*it = NULL;
	}
	m_Nodes.clear();

	delete m_pPath;
	m_pPath = NULL;
}

bool CKnot::OnRead(CXMLParser* pParser)
{
	//pParser->FindChildNode(NODE_KNOT);
	m_strKnotName = pParser->GetName();
	m_bActive = pParser->GetActive();
		if (pParser->FindChildNode(NODE_KEY_TIME, m_Time))
			pParser->EndXMLNode();
		if (pParser->FindChildNode(NODE_HIGH_LIGHT, m_bHightLight))
			pParser->EndXMLNode();
		{
			if (pParser->FindChildNode(NODE_TRANSNODE))
			{
				CTransNode* pNode = new CTransNode(this);
				pNode->OnRead(pParser);
				if (m_pTopNode == NULL)
				{
					m_pTopNode = pNode;
				}
			pParser->EndXMLNode();
			}
		}

	return __super::OnRead(pParser);
}

bool CKnot::OnWrite(CXMLParser* pParser)
{
	pParser->AddChildNode(NODE_KNOT);
	pParser->AddName(m_strKnotName);
	pParser->AddActive(m_bActive);
		pParser->AddChildNode(NODE_KEY_TIME, m_Time);
		pParser->EndXMLNode();
		pParser->AddChildNode(NODE_HIGH_LIGHT, m_bHightLight);
		pParser->EndXMLNode();
		{
			m_pTopNode->OnWrite(pParser);
		}
	pParser->EndXMLNode();

	return __super::OnWrite(pParser);
}

CTransPath* CKnot::operator-(CKnot& Knot)
{
	m_Diffs.clear();

	Back();

	CKnot* pRefObject = &Knot;

	CBone* pBone = m_pTopNode->GetBone();
	CBone* pBone2 = Knot.GetTopNode()->GetBone();

	// define start and end for path
	CVec start = CVec((*pBone)[0][0], (*pBone)[0][1], (*pBone)[0][2]);
	CVec end = CVec((*pBone2)[0][0], (*pBone2)[0][1], (*pBone2)[0][2]);
	CVec startDir = pBone->Direction();
	CVec endDir = pBone2->Direction();

	// define all node's differences
	Nodes::iterator it;
	Nodes::iterator it2;
	for (it = m_Nodes.begin(), it2 = Knot.m_Nodes.begin();
		it != m_Nodes.end(); it ++, it2 ++)
	{
		CTransNode* pNode = *it;
		CTransNode* pNode2 = *it2;
		if (pNode != NULL && pNode2 != NULL)
		{
			NodeDifference* pDiff = (*pNode) - (*pNode2);
			m_Diffs.push_back(pDiff);
		}
	}

	if (m_pPath != NULL)
	{
		delete m_pPath;
		m_pPath = NULL;
	}
	if (CTransPath::IsLinearPath(startDir, endDir))
	{
		m_pPath = new CLinearPath();
	}
	else
	{
		CCirclePath* pCirclePath = new CCirclePath();
		pCirclePath->GetStartTangent() = startDir;
		pCirclePath->GetEndTangent() = endDir;
		m_pPath = pCirclePath;
	}
	(*m_pPath->GetStart()) = start;
	(*m_pPath->GetEnd()) = end;

	Rollback();

	return m_pPath;
}

CKnot* CKnot::Copy()
{
	CKnot* pNew = new CKnot(m_pParent);

	// native information
	pNew->m_Time = m_Time;
	pNew->m_min = m_min;
	pNew->m_max = m_max;
	pNew->m_bHightLight = m_bHightLight;
	pNew->m_bExpanded = m_bExpanded;
	pNew->m_Time = m_Time;

	return pNew;
}

void CKnot::Render()
{
	if (!IsVisibility()) return;

	if (IsHighLight())
	{
		CSKGlobal::GetGraphPlotter()->SetColor(255.0f, 0.0f, 0.0f);
	}
	else
	{
		CSKGlobal::GetGraphPlotter()->SetColor(255.0f,255.0f,255.0f);
	}

	for (Nodes::iterator it = m_Nodes.begin();
		it != m_Nodes.end(); it ++)
	{
		CTransNode* pNode = *it;
		pNode->Render();
	}
}

CGBox& CKnot::GetRangeBox()
{
	m_min = CVec(1000000000, 1000000000, 1000000000);
	m_max = CVec(-1000000000, -1000000000, -1000000000);
	
	for (Nodes::iterator it = m_Nodes.begin();
		it != m_Nodes.end(); it ++)
	{
		CTransNode* pNode = *it;
		CGBox& pTempBox = pNode->GetRangeBox();

		CVec tempMin = pTempBox.GetMin();
		CVec tempMax = pTempBox.GetMax();

		if (m_min[0] > tempMin[0])
			m_min.SetX(tempMin[0]);
		if (m_min[1] > tempMin[1])
			m_min.SetY(tempMin[1]);
		if (m_min[2] > tempMin[2])
			m_min.SetZ(tempMin[2]);
		if (m_max[0] < tempMax[0])
			m_max.SetX(tempMax[0]);
		if (m_max[1] < tempMax[1])
			m_max.SetY(tempMax[1]);
		if (m_max[2] < tempMax[2])
			m_max.SetZ(tempMax[2]);
	}

	m_oRangeBox = CGBox(m_min[0], m_min[1], m_min[2],
		m_max[0], m_max[1], m_max[2]);
	return m_oRangeBox;
}

void CKnot::HighLight(bool bHighLight)
{
	__super::HighLight(bHighLight);
	for (Nodes::iterator it = m_Nodes.begin();
		it != m_Nodes.end(); it ++)
	{
		CTransNode* pNode = *it;
		if (bHighLight)
		{
			CSKGlobal::GetHighLightSet()->Add(pNode);
		}
		else
		{
			CSKGlobal::GetHighLightSet()->Delete(pNode);
		}
	}
}

void CKnot::SetActive(bool bActive)
{
	if (bActive)
	{
		Knots* pKnots = m_pParent->GetKnots();
		for (Knots::iterator itComp = pKnots->begin();
			itComp != pKnots->end(); itComp ++)
		{
			if (*itComp == this) continue;
			(*itComp)->SetActive(false);
		}
	}

	__super::SetActive(bActive);
	for (Nodes::iterator it = m_Nodes.begin();
		it != m_Nodes.end(); it ++)
	{
		CTransNode* pNode = *it;
		pNode->SetActive(bActive);
	}
}

void CKnot::UpdateExpandStatus(CTreeCtrl* pTree)
{
	__super::UpdateExpandStatus(pTree);
	for (Nodes::iterator it = m_Nodes.begin();
		it != m_Nodes.end(); it ++)
	{
		CTransNode* pNode = *it;
		pNode->UpdateExpandStatus(pTree);
	}
}

void CKnot::Expand(CTreeCtrl* pTree)
{
	if (IsExpand())
	{
		__super::Expand(pTree);
		for (Nodes::iterator it = m_Nodes.begin();
			it != m_Nodes.end(); it ++)
		{
			CTransNode* pNode = *it;
			pNode->Expand(pTree);
		}
	}
}

void CKnot::Back()
{
	for (Nodes::iterator it = m_Nodes.begin();
		it != m_Nodes.end(); it ++)
	{
		CTransNode* pNode = *it;
		pNode->Back();
	}
}

void CKnot::Rollback()
{
	for (Nodes::iterator it = m_Nodes.begin();
			it != m_Nodes.end(); it ++)
	{
		CTransNode* pNode = *it;
		pNode->Rollback();
	}
}

CTransNode* CKnot::GetTopNode()
{
	if (m_pTopNode == NULL)
		return m_Nodes[0];
	else
		return m_pTopNode;
}